﻿using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace FastDev
{
    public abstract class GoapAgent : MonoBehaviour, IGoapAgent
    {
        public GoapAction CurAction { get; set; }

        public abstract GoapAction Goal { get; protected set; }
        public abstract List<GoapAction> GoapActions { get; protected set; }

        public GoapState GoapState { get; protected set; } = new GoapState();

        public GameObject GameObject => base.gameObject;

        private Queue<GoapAction> queueGoapActions;

        public void StartPlan()
        {
            GoapPlanner.Plan(this, Goal, GoapActions);
        }

        public virtual void OnActionStart(GoapAction goapAction)
        {
            goapAction.OnStart();
        }

        public virtual void OnActionUpdate(GoapAction goapAction)
        {
            if (GoapState.Contains(goapAction.Effect))
            {
                OnActionDone(goapAction);
                return;
            }

            string unmatchedKey = "";
            if (!GoapState.Contains(goapAction.PreCondition, ref unmatchedKey))
            {
                OnActionFailed(goapAction);
                Debug.LogError("unmatchedKey: " + unmatchedKey);
                return;
            }

            goapAction.OnUpdate();
        }

        public virtual void OnActionDone(GoapAction goapAction)
        {
            goapAction.OnDone();
            if (goapAction == Goal)
            {
                OnPlanDone();
            }
            CurAction = null;
        }


        public virtual void OnActionFailed(GoapAction goapAction)
        {
            goapAction.OnFailed();
            CurAction = null;
        }

        public virtual void OnPlanFailed(string actionName)
        {
            Debug.LogError("OnPlanFailed:" + actionName);
        }

        public virtual void OnStartPlanSuccess(Queue<GoapAction> queueGoapActions)
        {
            this.queueGoapActions = queueGoapActions;
        }

        public virtual void OnPlanDone()
        {
            Debug.Log("OnPlanDone");
            CurAction = null;
        }

        protected virtual void Update()
        {
            if (queueGoapActions == null)
                return;
            if (queueGoapActions.Count > 0 && CurAction == null)
            {
                CurAction = queueGoapActions.Dequeue();
                CurAction.OnReset();
            }
            if (CurAction != null)
            {
                switch (CurAction.GoapActionState)
                {
                    case GoapActionState.None:
                        OnActionStart(CurAction);
                        break;
                    case GoapActionState.OnStart:
                    case GoapActionState.OnUpdate:
                        OnActionUpdate(CurAction);
                        break;
                }
            }
        }
    }
}
